package ch.epfl.lara.pm.analyze.set;

import scala.collection.mutable.HashMap


class PatternMap extends Cloneable{
  import ch.epfl.lara.pm.analyze.Util.freshSetName
  
  /**
   * Bound the path to specific position of a pattern to a metavariable that represent the abstract type
   * of an element that belong to this specific path.
   */
  private var path2metaset: HashMap[String,String] = new HashMap[String,String]
        
  /**
   * Bound all generated set metavariable to its most generic type. 
   */
  private val metaset2stype: HashMap[String,List[String]] = new HashMap[String,List[String]]
  
  /**
   * Add the pair (path,metaset) to the path2metaset map.
   */
  def addPath(path: String, metaset: String) = {
    path2metaset += ((path,metaset))
  }
  
    
  /**
   * Add the pair (metaset,tpe) to the metaset2stype map.
   */
  def addMetaset(metaset: String,tpe: String) = {
    metaset2stype.get(metaset) match {
      case None => metaset2stype.update(metaset,List(tpe))
      case Some(tpes) => tpes.contains(tpe) match {
        case true => ()
        case false => metaset2stype.update(metaset,tpe :: tpes)
      }
    }
  }
  

  /**
   * The two mappings are tightly interweaved. 
   * Check if the path exists in the path2metaset map. If a match is found, then do nothing. Otherwise,
   * update both map with a fresh metaset variable. 
   */
  def existsMetasetOrUpdate(path: String,tpe: String) =  {
    if(!isPathInMap(path)) {
      val metaset = freshSetName
      addPath(path,metaset)
      addMetaset(metaset,tpe)
    } else {
      addMetaset(path2metaset.get(path).get,tpe)
    }
  }       
   
   
  def isPathInMap(path: String) = path2metaset.contains(path)
  
  
  /*
  def getCompleteSetWithRefinement(path: String, tpe: String) = {
    val meta = path2metaset.get(path).getOrElse(error("check class "+this))
    (for((mset,cset)<-metaset2stype.elements) yield {
      if(mset==meta) tpe
      else cset
    }).toList
  }
  */
    
  /**
   * Obtain the set (as a cartesian product) that represent the complete pattern matching expression
   */
  def getCompleteSet: List[List[String]] = metaset2stype.values.toList  
  
  /**
   * Obtain the metaset (as a cartesian product) that represent the complete pattern matching expression
   */
  def getCompleteMetaSet: List[String] = 
    metaset2stype.keys.toList
  
  def getConcreteSet(meta: String): Option[List[String]] = 
    metaset2stype.get(meta)
    
  def getMetaset(path: String): Option[String] = 
    path2metaset.get(path)
  
  override def toString = {
    "PatternMap "+metaset2stype.toString
  }
  
  override def clone: PatternMap = {
    val copy = new PatternMap
    for(pair<-path2metaset.elements) copy.addPath(pair._1,pair._2)
    for(pair<-metaset2stype.elements;set<-pair._2) copy.addMetaset(pair._1,set)
    copy
  }
}
